package vues;
/*
 * Copyright (c) 2003, the JUNG Project and the Regents of the University of
 * California All rights reserved.
 * 
 * This software is open-source under the BSD license; see either "license.txt"
 * or http://jung.sourceforge.net/license.txt for a description.
 * 
 */


import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.awt.print.Printable;
import java.io.File;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.Map.Entry;

import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

import logique.reseau.Troncon;
import logique.reseau.Ville;
import controleur.Controleur;
import edu.uci.ics.jung.graph.ArchetypeVertex;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.decorators.DefaultToolTipFunction;
import edu.uci.ics.jung.graph.decorators.EdgeShape;
import edu.uci.ics.jung.graph.decorators.EllipseVertexShapeFunction;
import edu.uci.ics.jung.graph.decorators.VertexIconAndShapeFunction;
import edu.uci.ics.jung.graph.decorators.VertexStringer;
import edu.uci.ics.jung.graph.impl.AbstractSparseEdge;
import edu.uci.ics.jung.graph.impl.SparseGraph;
import edu.uci.ics.jung.graph.impl.SparseVertex;
import edu.uci.ics.jung.graph.impl.UndirectedSparseEdge;
import edu.uci.ics.jung.visualization.AbstractLayout;
import edu.uci.ics.jung.visualization.DefaultGraphLabelRenderer;
import edu.uci.ics.jung.visualization.DefaultSettableVertexLocationFunction;
import edu.uci.ics.jung.visualization.FRLayout;
import edu.uci.ics.jung.visualization.PluggableRenderer;
import edu.uci.ics.jung.visualization.ShapePickSupport;
import edu.uci.ics.jung.visualization.StaticLayout;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.control.CrossoverScalingControl;
import edu.uci.ics.jung.visualization.control.ModalGraphMouse;
import edu.uci.ics.jung.visualization.control.ScalingControl;
/**
 * Shows how easy it is to create a graph editor with JUNG.
 * Mouse modes and actions are explained in the help text.
 * The application version of GraphEditorDemo provides a
 * File menu with an option to save the visible graph as
 * a jpeg file.
 * 
 * @author Tom Nelson - RABA Technologies
 * 
 */
public class GraphEditorDemo implements Printable {

    /**
     * the graph
     */
    Graph graph;
    
    AbstractLayout layout;

    /**
     * the visual component and renderer for the graph
     */
    VisualizationViewer vv;
    
    DefaultSettableVertexLocationFunction vertexLocations;
    Container content;
    String instructions =
        "<html>"+
        "<h3>All Modes:</h3>"+
        "<ul>"+
        "<li>Right-click an empty area for <b>Create Vertex</b> popup"+
        "<li>Right-click on a Vertex for <b>Delete Vertex</b> popup"+
        "<li>Right-click on a Vertex for <b>Add Edge</b> menus <br>(if there are selected Vertices)"+
        "<li>Right-click on an Edge for <b>Delete Edge</b> popup"+
        "<li>Mousewheel scales with a crossover value of 1.0.<p>"+
        "     - scales the graph layout when the combined scale is greater than 1<p>"+
        "     - scales the graph view when the combined scale is less than 1"+

        "</ul>"+
        "<h3>Editing Mode:</h3>"+
        "<ul>"+
        "<li>Left-click an empty area to create a new Vertex"+
        "<li>Left-click on a Vertex and drag to another Vertex to create an Undirected Edge"+
        "<li>Shift+Left-click on a Vertex and drag to another Vertex to create a Directed Edge"+
        "</ul>"+
        "<h3>Picking Mode:</h3>"+
        "<ul>"+
        "<li>Mouse1 on a Vertex selects the vertex"+
        "<li>Mouse1 elsewhere unselects all Vertices"+
        "<li>Mouse1+Shift on a Vertex adds/removes Vertex selection"+
        "<li>Mouse1+drag on a Vertex moves all selected Vertices"+
        "<li>Mouse1+drag elsewhere selects Vertices in a region"+
        "<li>Mouse1+Shift+drag adds selection of Vertices in a new region"+
        "<li>Mouse1+CTRL on a Vertex selects the vertex and centers the display on it"+
        "</ul>"+
        "<h3>Transforming Mode:</h3>"+
        "<ul>"+
        "<li>Mouse1+drag pans the graph"+
        "<li>Mouse1+Shift+drag rotates the graph"+
        "<li>Mouse1+CTRL(or Command)+drag shears the graph"+
        "</ul>"+
        "</html>";
    
    /**
     * create an instance of a simple graph with popup controls to
     * create a graph.
     * 
     */
    public GraphEditorDemo(Controleur ct) {
       
        // allows the precise setting of initial vertex locations
    	vertexLocations = new DefaultSettableVertexLocationFunction();
        
        // create a simple graph for the demo
        graph = new SparseGraph();
        
        Hashtable<String, SparseVertex> map = new Hashtable<String, SparseVertex>();
        Hashtable<SparseVertex, Ville> map2 = new Hashtable<SparseVertex, Ville>();
        Hashtable<SparseVertex, Icon> iconMap = new Hashtable<SparseVertex, Icon>();
        Hashtable<String, Ville> villes ;
        Hashtable<AbstractSparseEdge, Troncon> mapEdge = new Hashtable<AbstractSparseEdge, Troncon>();
        if  ( ct.getNbVilles() < 30){
        	villes = ct.getVilles();
	        for (Iterator<Entry<String, Ville>> iterator = villes.entrySet().iterator(); iterator.hasNext();) { 
	        	Entry<String, Ville> entry = iterator.next();
	        	SparseVertex v = new SparseVertex();
	        	graph.addVertex(v);
	        	map.put(entry.getValue().getNom(), v);
	        	map2.put(v, entry.getValue());
	
	            
	            try {
	            	Icon petite =  new ImageIcon(GraphEditorDemo.class.getResource("/fleches/petite.gif"));
	            	Icon moyenne =  new ImageIcon(GraphEditorDemo.class.getResource("/fleches/moyenne.gif"));
	            	Icon grande =  new ImageIcon(GraphEditorDemo.class.getResource("/fleches/grande.gif"));
	            	if (entry.getValue().getTaille() != null){
	            		if (entry.getValue().getTaille().intitule() == "petite"){
	            			iconMap.put(v, petite);
	            		}
	            		else if (entry.getValue().getTaille().intitule() == "moyenne"){
	            			iconMap.put(v, moyenne);
	            		}
	            		else if (entry.getValue().getTaille().intitule() == "grande"){
	            			iconMap.put(v, grande);
	            		}
	            	}else{
	            		iconMap.put(v, petite);
	            	}
	                
	                
	            } catch(Exception ex) {
	                System.err.println("You need slashdoticons.jar in your classpath to see the image ");
	            }
	        }
	        try {
				for (Troncon troncon:ct.getAllTroncons()){
					Ville ville1 = troncon.getVille1();
					Ville ville2 = troncon.getVille2();
					SparseVertex vertex1 = map.get(ville1.getNom());
					SparseVertex vertex2 = map.get(ville2.getNom());
					UndirectedSparseEdge e = new UndirectedSparseEdge(vertex1, vertex2);
					mapEdge.put(e, troncon);
					graph.addEdge(e);
				}
			} catch (Exception e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
        }else{
        	JFrame frame = new JFrame("Erreur");
	        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			JOptionPane.showMessageDialog(frame, "Le graphe contient trop de villes, impossible d'afficher");
		
        }
	        PluggableRenderer pr = new PluggableRenderer();
	        //this.layout = new StaticLayout(graph);
	        FRLayout frlayout = new FRLayout(graph);
	//        frlayout.setMaxIterations(100); 
	        frlayout.initialize(new Dimension(550,450));
	        vv =  new VisualizationViewer(frlayout, pr);
	        for (Iterator<Entry<String, SparseVertex>> iterator = map.entrySet().iterator(); iterator.hasNext();) { 
	        	Entry<String, SparseVertex> entry = iterator.next();        	
	        	vertexLocations.setLocation(entry.getValue() , frlayout.getLocation(entry.getValue()));
	//        	System.out.println("Location:");
	//        	System.out.println(frlayout.getLocation(entry.getValue()));
	//        	System.out.println("Coordinate:");
	//        	System.out.println(vv.transform(frlayout.getLocation(entry.getValue())));
	        	
	        }        
	        this.layout = new StaticLayout(graph);
	//        this.layout.initialize(new Dimension(600,600));
	//        for (Iterator<Entry<String, SparseVertex>> iterator = map.entrySet().iterator(); iterator.hasNext();) { 
	//        	Entry<String, SparseVertex> entry = iterator.next();
	//        	vertexLocations.setLocation(entry.getValue() , this.layout.getLocation(entry.getValue()));
	//        	System.out.println(frlayout.getLocation(entry.getValue()));
	//        }
	//        vertexLocations.setLocation(map.get("paris"), new Point(0, 0));
	        this.layout.initialize(new Dimension(600,600), vertexLocations);
	        
	//        System.out.println("After init : \n");
	//        for (Iterator<Entry<String, SparseVertex>> iterator = map.entrySet().iterator(); iterator.hasNext();) { 
	//        	Entry<String, SparseVertex> entry = iterator.next();
	////        	vertexLocations.setLocation(entry.getValue() , frlayout.getLocation(entry.getValue()));
	//        	System.out.println(frlayout.getLocation(entry.getValue()));
	//        }  
	        final VertexStringerImpl vertexStringerImpl = 
	            new VertexStringerImpl(map2);
	//        System.out.println(vertexStringerImpl.getLabel(map.get("paris")));
	        pr.setVertexStringer(vertexStringerImpl);
	        pr.setGraphLabelRenderer(new DefaultGraphLabelRenderer(Color.cyan, Color.cyan));
	        
	        
	        final VertexIconAndShapeFunction vertexImagerAndShapeFunction =
	            new VertexIconAndShapeFunction(new EllipseVertexShapeFunction());
	        vertexImagerAndShapeFunction.setIconMap(iconMap);
	        pr.setVertexShapeFunction(vertexImagerAndShapeFunction);
	        pr.setVertexIconFunction(vertexImagerAndShapeFunction);
	        
	        
	        vv =  new VisualizationViewer(layout, pr);
	        vv.setBackground(Color.white);
	        vv.setPickSupport(new ShapePickSupport());
	        pr.setEdgeShapeFunction(new EdgeShape.BentLine());
	    //    pr.setEdge
	
	
	        vv.setToolTipFunction(new DefaultToolTipFunction());
	        
	
	       
	        
	        final EditingMouse graphMouse = new EditingMouse(map2, ct);
	        
	        // the EditingGraphMouse will pass mouse event coordinates to the
	        // vertexLocations function to set the locations of the vertices as
	        // they are created
	        
	        graphMouse.setVertexLocations(vertexLocations);
	        vv.setGraphMouse(graphMouse);
	        graphMouse.add(new EditingPopupVilleGraphMouse(vertexLocations, map2, iconMap, mapEdge, ct));
	        graphMouse.setMode(ModalGraphMouse.Mode.EDITING);
	        
	        final ScalingControl scaler = new CrossoverScalingControl();
	        JButton plus = new JButton("+");
	        plus.addActionListener(new ActionListener() {
	            public void actionPerformed(ActionEvent e) {
	                scaler.scale(vv, 1.1f, vv.getCenter());
	            }
	        });
	        JButton minus = new JButton("-");
	        minus.addActionListener(new ActionListener() {
	            public void actionPerformed(ActionEvent e) {
	                scaler.scale(vv, 1/1.1f, vv.getCenter());
	            }
	        });
	        
	        JButton help = new JButton("Help");
	        help.addActionListener(new ActionListener() {
	
	            public void actionPerformed(ActionEvent e) {
	                JOptionPane.showMessageDialog(vv, instructions);
	            }});
	
	        JPanel controls = new JPanel();
	        controls.add(plus);
	        controls.add(minus);
	        JComboBox modeBox = graphMouse.getModeComboBox();
	        controls.add(modeBox);
	        controls.add(help);
        
    }
    
    /**
     * copy the visible part of the graph to a file as a jpeg image
     * @param file
     */
    public void writeJPEGImage(File file) {
        int width = vv.getWidth();
        int height = vv.getHeight();

        BufferedImage bi = new BufferedImage(width, height,
                BufferedImage.TYPE_INT_RGB);
        Graphics2D graphics = bi.createGraphics();
        vv.paint(graphics);
        graphics.dispose();
        
        try {
            ImageIO.write(bi, "jpeg", file);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public int print(java.awt.Graphics graphics,
            java.awt.print.PageFormat pageFormat, int pageIndex)
            throws java.awt.print.PrinterException {
        if (pageIndex > 0) {
            return (Printable.NO_SUCH_PAGE);
        } else {
            java.awt.Graphics2D g2d = (java.awt.Graphics2D) graphics;
            vv.setDoubleBuffered(false);
            g2d.translate(pageFormat.getImageableX(), pageFormat
                    .getImageableY());

            vv.paint(g2d);
            vv.setDoubleBuffered(true);

            return (Printable.PAGE_EXISTS);
        }
    }
    
    /**
     * A simple implementation of VertexStringer that
     * gets Vertex labels from a Map  
     * 
     * @author Tom Nelson - RABA Technologies
     *
     *
     */
    public static class VertexStringerImpl implements VertexStringer {
        
    	Hashtable<SparseVertex, Ville> map = new Hashtable<SparseVertex, Ville>();
        
        boolean enabled = true;
        
        public VertexStringerImpl(Hashtable<SparseVertex, Ville> map) {
            this.map = map;
        }
        
        /* (non-Javadoc)
         * @see edu.uci.ics.jung.graph.decorators.VertexStringer#getLabel(edu.uci.ics.jung.graph.Vertex)
         */
        public String getLabel(ArchetypeVertex v) {
            if(isEnabled()) {
            	if (map.get(v) != null){
            		return (String)map.get(v).getNom();
            	} else {
            		return "marche pas";
            	}
            } else {
                return "";
            }
        }
        
        /**
         * @return Returns the enabled.
         */
        public boolean isEnabled() {
            return enabled;
        }
        
        /**
         * @param enabled The enabled to set.
         */
        public void setEnabled(boolean enabled) {
            this.enabled = enabled;
        }
    }

    
    public static class LayeredIcon extends ImageIcon {

		Set iconSet = new LinkedHashSet();

		public LayeredIcon(Image image) {
		    super(image);
		}

		public void paintIcon(Component c, Graphics g, int x, int y) {
            super.paintIcon(c, g, x, y);
            Dimension d = new Dimension(getIconWidth(), getIconHeight());
			for (Iterator iterator = iconSet.iterator(); iterator.hasNext();) {
				Icon icon = (Icon) iterator.next();
                 Dimension id = new Dimension(icon.getIconWidth(), icon.getIconHeight());
                 int dx = (d.width - id.width)/2;
                 int dy = (d.height - id.height)/2;
				icon.paintIcon(c, g, x+dx, y+dy);
			}
		}

		public void add(Icon icon) {
			iconSet.add(icon);
		}

		public boolean remove(Icon icon) {
			return iconSet.remove(icon);
		}
	}
    
    
    /**
     * a driver for this demo
     */
	public static void main(String[] args) {
		Controleur ct = new Controleur();
	    JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        ct.choisirReseau("/home/chewbie/workspace/roadguide@GoogleCode/exemples/reseau_75v_2000t.xml");
      //  System.out.println(ct.toString());
        final GraphEditorDemo demo = new GraphEditorDemo(ct);
        
		
	//	System.out.println(ct.toString());
        frame.getContentPane().add(demo.vv);
        frame.pack();
        frame.setVisible(true);
	
		
	}
}